﻿Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.IO
Imports System.Net
Imports System.Runtime.Serialization.Json
Imports System.Windows
Imports VMWorkshop.Silverlight.VMWorkshop.Domain

Public Class DemoViewModel
    Implements INotifyPropertyChanged
    ' Events
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    ' Private Fields
    Private _listServiceLocation As Uri = Nothing
    Private _editServiceLocation As Uri = Nothing
    Private _persistLocation As Uri = Nothing
    Private _updateMessageVisibility As Visibility = Visibility.Collapsed
    Private _editFormVisibility As Visibility = Visibility.Collapsed
    Private _productsGridVisibility As Visibility = Visibility.Collapsed
    Private _selectedProduct As New ProductEditView()
    Private _client As WebClient = Nothing
    Private _products As IEnumerable(Of ProductListView) = Nothing

    ' Public Properties
    Public Property SelectedProduct() As ProductEditView
        Get
            Return Me._selectedProduct
        End Get
        Set(ByVal value As ProductEditView)
            If Me._selectedProduct IsNot value Then
                Me._selectedProduct = value
                Me.RaisePropertyChangedEvent("SelectedProduct")
            End If
        End Set
    End Property

    Public Property Products() As IEnumerable(Of ProductListView)
        Get
            Return Me._products
        End Get
        Set(ByVal value As IEnumerable(Of ProductListView))
            If Me._products IsNot value Then
                Me._products = value
                Me.RaisePropertyChangedEvent("Products")
            End If
        End Set
    End Property

    Public ReadOnly Property ListServiceLocation() As Uri
        Get
            Return Me._listServiceLocation
        End Get
    End Property

    Public ReadOnly Property EditServiceLocation() As Uri
        Get
            Return Me._editServiceLocation
        End Get
    End Property

    Public Property UpdateMessageVisibility() As Visibility
        Get
            Return Me._updateMessageVisibility
        End Get
        Set(ByVal value As Visibility)
            If Me._updateMessageVisibility <> value Then
                Me._updateMessageVisibility = value
                Me.RaisePropertyChangedEvent("UpdateMessageVisibility")
            End If
        End Set
    End Property

    Public Property EditFormVisibility() As Visibility
        Get
            Return Me._editFormVisibility
        End Get
        Set(ByVal value As Visibility)
            If Me._editFormVisibility <> value Then
                Me._editFormVisibility = value
                Me.RaisePropertyChangedEvent("EditFormVisibility")
            End If
        End Set
    End Property

    Public Property ProductsGridVisibility() As Visibility
        Get
            Return Me._productsGridVisibility
        End Get
        Set(ByVal value As Visibility)
            If Me._productsGridVisibility <> value Then
                Me._productsGridVisibility = value
                Me.RaisePropertyChangedEvent("ProductsGridVisibility")
            End If
        End Set
    End Property

    ' Constructor
    Public Sub New(ByVal listServiceLocation As Uri, ByVal editServiceLocation As Uri, ByVal persistLocation As Uri)
        Me._listServiceLocation = listServiceLocation
        Me._editServiceLocation = editServiceLocation
        Me._persistLocation = persistLocation

        Me._client = New WebClient()
        Me.SetAcceptHeader()

        Me.SelectedProduct = New ProductEditView()
    End Sub

    ' Public interface methods and callbacks
    Public Sub GetProducts()
        If Not Me._client.IsBusy Then
            Me.ClearOpenReadCompletedEvents()
            AddHandler Me._client.OpenReadCompleted, AddressOf Me.GetProductsCompleted
            Me._client.OpenReadAsync(Me._listServiceLocation)
        End If
    End Sub

    Private Sub GetProductsCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
        Me.Products = Me.ParseJsonList(Of ProductListView)(e.Result)
        Me.ProductsGridVisibility = Visibility.Visible
    End Sub

    Public Sub GetSelectedProduct(ByVal productId As Integer)
        If Not Me._client.IsBusy Then
            Me.ClearOpenReadCompletedEvents()
            AddHandler Me._client.OpenReadCompleted, AddressOf Me.GetSelectedProductCompleted
            Me.SetAcceptHeader()

            Dim uri As String = Me._editServiceLocation.OriginalString + String.Format("/{0}", productId)
            Dim kind As UriKind = If(Me._editServiceLocation.IsAbsoluteUri, UriKind.Absolute, UriKind.Relative)
            Me._client.OpenReadAsync(New Uri(uri, kind))

            Me.UpdateMessageVisibility = Visibility.Collapsed
        End If
    End Sub

    Private Sub GetSelectedProductCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
        Me.SelectedProduct = Me.ParseJsonSingle(Of ProductEditView)(e.Result)
        Me.EditFormVisibility = Visibility.Visible
    End Sub

    Public Sub Persist()
        Dim post As New WebClientPost(Me._persistLocation)
        AddHandler post.PostComplete, AddressOf Me.PersistCompleted
        post.AddDataItem(Me.SelectedProduct)
        post.Send()
    End Sub

    Private Sub PersistCompleted(ByVal sender As Object, ByVal e As EventArgs)
        Me.EditFormVisibility = Visibility.Collapsed
        Me.UpdateMessageVisibility = Visibility.Visible
    End Sub

    ' Utility Methods
    Protected Overridable Sub RaisePropertyChangedEvent(ByVal ParamArray propertyNames As String())
        For Each name As String In propertyNames
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
        Next
    End Sub

    Private Sub SetAcceptHeader()
        Me._client.Headers(HttpRequestHeader.Accept) = RequestHeaders.Json
    End Sub

    Private Sub ClearOpenReadCompletedEvents()
        RemoveHandler Me._client.OpenReadCompleted, AddressOf Me.GetProductsCompleted
        RemoveHandler Me._client.OpenReadCompleted, AddressOf Me.GetSelectedProductCompleted
    End Sub

    Private Function ParseJsonList(Of T)(ByVal stream As Stream) As IEnumerable(Of T)
        Dim serializer As New DataContractJsonSerializer(GetType(T()))
        Dim result As T() = DirectCast(serializer.ReadObject(stream), T())
        Return result
    End Function

    Private Function ParseJsonSingle(Of T)(ByVal stream As Stream) As T
        Dim serializer As New DataContractJsonSerializer(GetType(T))
        Dim result As T = DirectCast(serializer.ReadObject(stream), T)
        Return result
    End Function
End Class